package eu.vranckaert.workRegistrationWidget.service.impl;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.util.Log;
import java.util.Date;
import android.widget.Toast;
import com.google.inject.Inject;
import eu.vranckaert.workRegistrationWidget.R;
import eu.vranckaert.workRegistrationWidget.dao.TimeRegDao;
import eu.vranckaert.workRegistrationWidget.domain.TimeRegistration;
import eu.vranckaert.workRegistrationWidget.service.LocationService;
import eu.vranckaert.workRegistrationWidget.util.DateUtil;
import eu.vranckaert.workRegistrationWidget.util.Preferences;

/**
 * @author Dirk Vranckaert
 *         Date: 10-jun-2010
 *         Time: 16:32:22
 */
public class LocationServiceImpl implements LocationService {
    private static final String LOG_TAG = LocationServiceImpl.class.getName();

    private static final int GPS_UPDATE_RATE_MS  = 500;
    private static final int GPS_ACCURACY = 50;

    @Inject
    TimeRegDao timeRegDao;

    @Override
    public boolean determineLastKnownLocation(Context context, TimeRegistration timeRegistration) {
        boolean result = false;
        final LocationManager manager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
        Location lastKnownLocation = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

        if (lastKnownLocation != null) {
            Log.d(LOG_TAG, "Current location (LATITUDE): " + lastKnownLocation.getLatitude());
            Log.d(LOG_TAG, "Current location (LONGTITUDE): " + lastKnownLocation.getLongitude());
            setLocationOnTimeRegistration(context, lastKnownLocation, timeRegistration);
            result = true;
        } else {
            Log.d(LOG_TAG, "No location available");
            result = false;
        }

        return result;
    }

    @Override
    public void determineLocation(final Context context, final TimeRegistration timeRegistration) {
        Location timeRegLocation = null;
        final Date startDate = new Date();
        final int timeout = Preferences.getGpsLookupTimeout(context);
        final boolean lastKnownLocationBackup = Preferences.getLastKnownLocationAllowed(context);

        final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        LocationListener locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                int duration = DateUtil.calculateMinutesDuration(startDate, new Date()); //TODO use seconds instead of minutes!
                if (duration >= timeout) {
                    Log.d(LOG_TAG, "Timeout of " + timeout + " seconds has been reached. Stopping GPS lookup!");
                    locationManager.removeUpdates(this);
                    boolean result = false;
                    if (lastKnownLocationBackup) {
                        result = determineLastKnownLocation(context, timeRegistration);
                    }
                    if (!result) {
                        showMessage(context, R.string.widget_str_location_timeout);
                    }
                } else {
                    Log.d(LOG_TAG, "Location found, not checked to be ok yet: latitude:" + location.getLatitude() + " longtitude:" + location.getLongitude() + " accuracy:" + location.getAccuracy());
                    if (location.hasAccuracy() && location.getAccuracy() <= GPS_ACCURACY) {
                        locationManager.removeUpdates(this);
                        setLocationOnTimeRegistration(context, location, timeRegistration);
                    }
                }
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle bundle) {
                boolean result = false;
                Log.d(LOG_TAG, "Location status changed to " + status);
                switch (status) {
                    case LocationProvider.OUT_OF_SERVICE:
                        Log.d(LOG_TAG, "Location could not be retrieved because out of service");
                        locationManager.removeUpdates(this);
                        if (lastKnownLocationBackup) {
                            result = determineLastKnownLocation(context, timeRegistration);
                        }
                        if (!result) {
                            showMessage(context, R.string.widget_str_location_out_of_service);
                        }
                        break;
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        Log.d(LOG_TAG, "Location could not be retrieved because temporarily unavailable");
                        locationManager.removeUpdates(this);
                        if (lastKnownLocationBackup) {
                            result = determineLastKnownLocation(context, timeRegistration);
                        }
                        if (!result) {
                            showMessage(context, R.string.widget_str_location_unavailable);
                        }
                        break;
                }
            }

            @Override
            public void onProviderEnabled(String s) {}

            @Override
            public void onProviderDisabled(String s) {
                Log.d(LOG_TAG, "Location not found because provider is disabled");
                locationManager.removeUpdates(this);
                showMessage(context, R.string.widget_str_location_provider_disabled);
            }
        };

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_RATE_MS, GPS_ACCURACY, locationListener);
    }

    private void showMessage(Context context, int messageId) {
        Toast.makeText(context, messageId, Toast.LENGTH_LONG).show();
    }

    private void setLocationOnTimeRegistration(Context context, Location location, TimeRegistration timeRegistration) {
        Log.d(LOG_TAG, "Location found! Longtitude: " + location.getLongitude() + " Latitude: " + location.getLatitude());
        boolean startLocation;

        if (timeRegistration.getEndDate() != null && timeRegistration.getEndDate().getTime() > 0L) {
            startLocation = false;
        } else {
            startLocation = true;
        }

        timeRegDao.updateWithLocation(context, timeRegistration, location, startLocation);
    }
}